TypeScript'ning 'infer' kalit so'ziga chuqur sho'ng'ish, kuchli tip manipulyatsiyalari va kodning aniqligini oshirish uchun shartli tiplarda uning ilg'or qo'llanilishini o'rganish.
Shartli Tiplarni Aniqlash: TypeScript'dagi 'infer' Kalit So'zini O'zlashtirish
TypeScript'ning tiplar tizimi mustahkam va qo'llab-quvvatlanishi oson kod yaratish uchun kuchli vositalarni taklif etadi. Ushbu vositalar orasida shartli tiplar murakkab tip munosabatlarini ifodalash uchun universal mexanizm sifatida ajralib turadi. infer kalit so'zi, ayniqsa, shartli tiplar doirasida ilg'or imkoniyatlarni ochib, murakkab tiplarni ajratib olish va manipulyatsiya qilish imkonini beradi. Ushbu batafsil qo'llanma infer'ning nozik jihatlarini o'rganadi va uni qo'llashni o'zlashtirishingizga yordam beradigan amaliy misollar va tushunchalarni taqdim etadi.
Shartli Tiplarni Tushunish
infer'ga sho'ng'ishdan oldin, shartli tiplarning asoslarini tushunib olish muhim. Shartli tiplar JavaScript'dagi ternar operatoriga o'xshash shartga bog'liq bo'lgan tiplarni aniqlash imkonini beradi. Sintaksis quyidagi shaklga ega:
T extends U ? X : Y
Bu yerda, agar T tipi U tipiga tayinlanishi mumkin bo'lsa, natijaviy tip X bo'ladi; aks holda, u Y bo'ladi.
Misol:
type IsString<T> = T extends string ? true : false;
type StringCheck = IsString<string>; // type StringCheck = true
type NumberCheck = IsString<number>; // type NumberCheck = false
Bu oddiy misol shartli tiplardan biror tipning satr (string) ekanligini aniqlash uchun qanday foydalanish mumkinligini ko'rsatadi. Bu tushuncha murakkabroq stsenariylarga ham tatbiq etiladi va infer kalit so'zi uchun yo'l ochadi.
'infer' Kalit So'zi bilan Tanishtiruv
infer kalit so'zi shartli tipning true shoxobchasi ichida tekshirilayotgan tipdan aniqlanishi mumkin bo'lgan tip o'zgaruvchisini kiritish uchun ishlatiladi. Bu sizga tipning ma'lum qismlarini ajratib olish va ularni natijaviy tipda ishlatish imkonini beradi.
Sintaksis:
T extends (infer R) ? X : Y
Ushbu sintaksisda R — bu T strukturasidan aniqlanadigan tip o'zgaruvchisi. Agar T namunaga mos kelsa, R aniqlangan tipni o'zida saqlaydi va natijaviy tip X bo'ladi; aks holda, u Y bo'ladi.
'infer'ni Qo'llashning Asosiy Misollari
1. Funksiyaning Qaytaradigan Tipini Aniqlash
Keng tarqalgan qo'llanish holatlaridan biri bu funksiyaning qaytaradigan tipini aniqlashdir. Bunga quyidagi shartli tip yordamida erishish mumkin:
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
Tushuntirish:
T extends (...args: any) => any: Bu cheklovTning funksiya ekanligini ta'minlaydi.(...args: any) => infer R: Bu namuna funksiyaga mos keladi va qaytariladigan tipniRsifatida aniqlaydi.R : any: AgarTfunksiya bo'lmasa, natijaviy tipanybo'ladi.
Misol:
function greet(name: string): string {
return `Hello, ${name}!`;
}
type GreetingReturnType = ReturnType<typeof greet>; // type GreetingReturnType = string
function calculate(a: number, b: number): number {
return a + b;
}
type CalculateReturnType = ReturnType<typeof calculate>; // type CalculateReturnType = number
Ushbu misol ReturnType ning greet va calculate funksiyalarining qaytaradigan tiplarini muvaffaqiyatli ajratib olganini ko'rsatadi.
2. Massiv Elementi Tipini Aniqlash
Yana bir tez-tez uchraydigan qo'llanish holati - bu massivning element tipini ajratib olish:
type ElementType<T> = T extends (infer U)[] ? U : never;
Tushuntirish:
T extends (infer U)[]: Bu namuna massivga mos keladi va element tipiniUsifatida aniqlaydi.U : never: AgarTmassiv bo'lmasa, natijaviy tipneverbo'ladi.
Misol:
type StringArrayElement = ElementType<string[]>; // type StringArrayElement = string
type NumberArrayElement = ElementType<number[]>; // type NumberArrayElement = number
type MixedArrayElement = ElementType<(string | number)[]>; // type MixedArrayElement = string | number
type NotAnArray = ElementType<number>; // type NotAnArray = never
Bu ElementType ning turli massiv tiplarining element tipini qanday qilib to'g'ri aniqlashini ko'rsatadi.
'infer'ni Ilg'or Qo'llash
1. Funksiya Parametrlarini Aniqlash
Qaytariladigan tipni aniqlashga o'xshab, siz infer va kortejlardan (tuples) foydalanib funksiya parametrlarini ham aniqlashingiz mumkin:
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
Tushuntirish:
T extends (...args: any) => any: Bu cheklovTning funksiya ekanligini ta'minlaydi.(...args: infer P) => any: Bu namuna funksiyaga mos keladi va parametr tiplariniPkorteji sifatida aniqlaydi.P : never: AgarTfunksiya bo'lmasa, natijaviy tipneverbo'ladi.
Misol:
function logMessage(message: string, level: 'info' | 'warn' | 'error'): void {
console.log(`[${level.toUpperCase()}] ${message}`);
}
type LogMessageParams = Parameters<typeof logMessage>; // type LogMessageParams = [message: string, level: "info" | "warn" | "error"]
function processData(data: any[], callback: (item: any) => void): void {
data.forEach(callback);
}
type ProcessDataParams = Parameters<typeof processData>; // type ProcessDataParams = [data: any[], callback: (item: any) => void]
Parameters parametr tiplarini kortej sifatida ajratib oladi, bunda funksiya argumentlarining tartibi va tiplari saqlanib qoladi.
2. Obyekt Tipidan Xususiyatlarni Ajratib Olish
infer shuningdek, obyekt tipidan ma'lum xususiyatlarni ajratib olish uchun ham ishlatilishi mumkin. Bu murakkabroq shartli tipni talab qiladi, ammo kuchli tip manipulyatsiyasini amalga oshirishga imkon beradi.
type PickByType<T, U> = {
[K in keyof T as T[K] extends U ? K : never]: T[K];
};
Tushuntirish:
K in keyof T: BuTtipining barcha kalitlari bo'ylab iteratsiya qiladi.T[K] extends U ? K : never: Bu shartli tipKkalitidagi xususiyatning tipi (ya'ni,T[K])Utipiga tayinlanishi mumkinligini tekshiradi. Agar shunday bo'lsa,Kkaliti natijaviy tipga kiritiladi; aks holda, uneveryordamida chiqarib tashlanadi.- Butun konstruksiya faqat tiplari
Uga mos keladigan xususiyatlarga ega bo'lgan yangi obyekt tipini yaratadi.
Misol:
interface Person {
name: string;
age: number;
city: string;
country: string;
}
type StringProperties = PickByType<Person, string>; // type StringProperties = { name: string; city: string; country: string; }
type NumberProperties = PickByType<Person, number>; // type NumberProperties = { age: number; }
PickByType mavjud tipdan faqat ma'lum bir tipdagi xususiyatlarni o'z ichiga olgan yangi tip yaratishga imkon beradi.
3. Ichki Joylashgan Tiplarni Aniqlash
infer chuqur joylashgan tuzilmalardan tiplarni ajratib olish uchun zanjir qilib va ichma-ich joylashtirilishi mumkin. Misol uchun, ichma-ich joylashgan massivning eng ichki elementining tipini ajratib olishni ko'rib chiqaylik.
type DeepArrayElement<T> = T extends (infer U)[] ? DeepArrayElement<U> : T;
Tushuntirish:
T extends (infer U)[]: BuTning massiv ekanligini tekshiradi va element tipiniUsifatida aniqlaydi.DeepArrayElement<U>: AgarTmassiv bo'lsa, tip rekursiv ravishdaDeepArrayElementniUelementi tipi bilan chaqiradi.T: AgarTmassiv bo'lmasa, tipTning o'zini qaytaradi.
Misol:
type NestedStringArray = string[][][];
type DeepString = DeepArrayElement<NestedStringArray>; // type DeepString = string
type MixedNestedArray = (number | string)[][][][];
type DeepMixed = DeepArrayElement<MixedNestedArray>; // type DeepMixed = string | number
type RegularNumber = DeepArrayElement<number>; // type RegularNumber = number
Ushbu rekursiv yondashuv massivdagi eng chuqur joylashuv darajasidagi elementning tipini ajratib olishga imkon beradi.
Haqiqiy Dunyodagi Qo'llanilishlar
infer kalit so'zi dinamik tip manipulyatsiyasi talab qilinadigan turli stsenariylarda qo'llaniladi. Mana bir nechta amaliy misollar:
1. Tip Xavfsizligi Ta'minlangan Event Emitter Yaratish
Siz infer yordamida hodisa ishlovchilarining to'g'ri ma'lumot tipini qabul qilishini ta'minlaydigan tip xavfsizligi ta'minlangan event emitter yaratishingiz mumkin.
type EventMap = {
'data': { value: string };
'error': { message: string };
};
type EventName<T extends EventMap> = keyof T;
type EventData<T extends EventMap, K extends EventName<T>> = T[K];
type EventHandler<T extends EventMap, K extends EventName<T>> = (data: EventData<T, K>) => void;
class EventEmitter<T extends EventMap> {
private listeners: { [K in EventName<T>]?: EventHandler<T, K>[] } = {};
on<K extends EventName<T>>(event: K, handler: EventHandler<T, K>): void {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event]!.push(handler);
}
emit<K extends EventName<T>>(event: K, data: EventData<T, K>): void {
this.listeners[event]?.forEach(handler => handler(data));
}
}
const emitter = new EventEmitter<EventMap>();
emitter.on('data', (data) => {
console.log(`Received data: ${data.value}`);
});
emitter.on('error', (error) => {
console.error(`An error occurred: ${error.message}`);
});
emitter.emit('data', { value: 'Hello, world!' });
emitter.emit('error', { message: 'Something went wrong.' });
Ushbu misolda EventData ma'lum bir hodisa nomi bilan bog'liq ma'lumotlar tipini ajratib olish uchun shartli tiplar va infer'dan foydalanadi, bu esa hodisa ishlovchilarining to'g'ri turdagi ma'lumotlarni qabul qilishini ta'minlaydi.
2. Tip Xavfsizligi Ta'minlangan Reducer'ni Amalga Oshirish
Siz holatni boshqarish (state management) uchun tip xavfsizligi ta'minlangan reducer funksiyasini yaratishda infer'dan foydalanishingiz mumkin.
type Action<T extends string, P = undefined> = P extends undefined
? { type: T }
: { type: T; payload: P };
type Reducer<S, A extends Action<string>> = (state: S, action: A) => S;
// Example Actions
type IncrementAction = Action<'INCREMENT'>;
type DecrementAction = Action<'DECREMENT'>;
type SetValueAction = Action<'SET_VALUE', number>;
// Example State
interface CounterState {
value: number;
}
// Example Reducer
const counterReducer: Reducer<CounterState, IncrementAction | DecrementAction | SetValueAction> = (
state: CounterState,
action: IncrementAction | DecrementAction | SetValueAction
): CounterState => {
switch (action.type) {
case 'INCREMENT':
return { ...state, value: state.value + 1 };
case 'DECREMENT':
return { ...state, value: state.value - 1 };
case 'SET_VALUE':
return { ...state, value: action.payload };
default:
return state;
}
};
// Usage
const initialState: CounterState = { value: 0 };
const newState1 = counterReducer(initialState, { type: 'INCREMENT' }); // newState1.value is 1
const newState2 = counterReducer(newState1, { type: 'SET_VALUE', payload: 10 }); // newState2.value is 10
Garchi bu misol to'g'ridan-to'g'ri `infer`'dan foydalanmasa-da, u murakkabroq reducer stsenariylari uchun poydevor yaratadi. `infer` har xil `Action` tiplaridan `payload` tipini dinamik ravishda ajratib olish uchun qo'llanilishi mumkin, bu esa reducer funksiyasi ichida qat'iyroq tip tekshiruvini ta'minlaydi. Bu, ayniqsa, ko'plab harakatlar va murakkab holat tuzilmalariga ega bo'lgan yirik ilovalarda foydalidir.
3. API Javoblaridan Dinamik Tiplarni Yaratish
API'lar bilan ishlaganda, siz API javoblarining tuzilmasidan avtomatik ravishda TypeScript tiplarini yaratish uchun infer'dan foydalanishingiz mumkin. Bu tashqi ma'lumotlar manbalari bilan ishlashda tip xavfsizligini ta'minlashga yordam beradi.
Keling, umumiy API javobidan ma'lumotlar tipini ajratib olishni istagan soddalashtirilgan stsenariyni ko'rib chiqaylik:
type ApiResponse<T> = {
status: number;
data: T;
message?: string;
};
type ExtractDataType<T> = T extends ApiResponse<infer U> ? U : never;
// Example API Response
type User = {
id: number;
name: string;
email: string;
};
type UserApiResponse = ApiResponse<User>;
type ExtractedUser = ExtractDataType<UserApiResponse>; // type ExtractedUser = User
ExtractDataType ApiResponse<U> dan U tipini ajratib olish uchun infer'dan foydalanadi va API tomonidan qaytarilgan ma'lumotlar tuzilmasiga tip xavfsizligi ta'minlangan holda kirish imkonini beradi.
Eng Yaxshi Amaliyotlar va Mulohazalar
- Aniqlik va O'qilishi Osonligi: Kodning o'qilishini yaxshilash uchun tushunarli tip o'zgaruvchi nomlaridan foydalaning (masalan, faqat
Ro'rnigaReturnType). - Ishlash Samaradorligi:
inferkuchli bo'lsa-da, uni haddan tashqari ko'p ishlatish tip tekshiruvi samadorligiga ta'sir qilishi mumkin. Undan oqilona foydalaning, ayniqsa katta kod bazalarida. - Xatoliklarga Ishlov Berish: Tip kutilgan namunaga mos kelmagan holatlarni boshqarish uchun shartli tipning
falseshoxobchasida har doim zaxira tipini (masalan,anyyokinever) taqdim eting. - Murakkablik: Ichma-ich joylashgan
inferifodalari bilan haddan tashqari murakkab shartli tiplardan saqlaning, chunki ularni tushunish va qo'llab-quvvatlash qiyinlashishi mumkin. Zarur bo'lganda kodingizni kichikroq, boshqarilishi osonroq tiplarga qayta ishlang (refaktoring qiling). - Testlash: Shartli tiplaringiz kutilganidek ishlashiga ishonch hosil qilish uchun ularni turli xil kirish tiplari bilan sinchkovlik bilan sinab ko'ring.
Global Mulohazalar
TypeScript va infer'ni global kontekstda ishlatganda, quyidagilarni hisobga oling:
- Lokalizatsiya va Internatsionalizatsiya (i18n): Tiplar turli xil lokallar va ma'lumotlar formatlariga moslashishi kerak bo'lishi mumkin. Lokalga xos talablarga asoslangan holda o'zgaruvchan ma'lumotlar tuzilmalarini dinamik ravishda boshqarish uchun shartli tiplar va `infer` dan foydalaning. Masalan, sanalar va valyutalar mamlakatlar bo'ylab turlicha ifodalanishi mumkin.
- Global Auditoriya uchun API Dizayni: API'laringizni global miqyosda foydalanish imkoniyatini hisobga olgan holda loyihalashtiring. Foydalanuvchining joylashuvidan qat'i nazar, tushunish va qayta ishlash oson bo'lgan izchil ma'lumotlar tuzilmalari va formatlaridan foydalaning. Tiplarning ta'riflari bu izchillikni aks ettirishi kerak.
- Vaqt Mintaqalari: Sanalar va vaqtlar bilan ishlaganda, vaqt mintaqalari farqlariga e'tiborli bo'ling. Vaqt mintaqalarini konvertatsiya qilish va turli mintaqalarda ma'lumotlarning to'g'ri ifodalanishini ta'minlash uchun tegishli kutubxonalardan (masalan, Luxon, date-fns) foydalaning. API javoblaringizda sana va vaqtni UTC formatida taqdim etishni ko'rib chiqing.
- Madaniy Farqlar: Ma'lumotlarni taqdim etish va talqin qilishdagi madaniy farqlardan xabardor bo'ling. Masalan, ismlar, manzillar va telefon raqamlari turli mamlakatlarda har xil formatlarga ega bo'lishi mumkin. Tiplaringizning ta'riflari ushbu o'zgarishlarga mos kela olishiga ishonch hosil qiling.
- Valyuta bilan ishlash: Pul qiymatlari bilan ishlaganda, izchil valyuta ifodasidan (masalan, ISO 4217 valyuta kodlari) foydalaning va valyuta konvertatsiyalarini to'g'ri bajaring. Aniqlik bilan bog'liq muammolarni oldini olish va to'g'ri hisob-kitoblarni ta'minlash uchun valyuta manipulyatsiyasi uchun mo'ljallangan kutubxonalardan foydalaning.
Masalan, turli mintaqalardan foydalanuvchi profillarini olayotganingizni va manzil formati mamlakatga qarab o'zgarishini tasavvur qiling. Foydalanuvchining joylashuviga qarab tip ta'rifini dinamik ravishda sozlash uchun shartli tiplar va `infer` dan foydalanishingiz mumkin:
type AddressFormat<CountryCode extends string> = CountryCode extends 'US'
? { street: string; city: string; state: string; zipCode: string; }
: CountryCode extends 'CA'
? { street: string; city: string; province: string; postalCode: string; }
: { addressLines: string[]; city: string; country: string; };
type UserProfile<CountryCode extends string> = {
id: number;
name: string;
email: string;
address: AddressFormat<CountryCode>;
countryCode: CountryCode; // Add country code to profile
};
// Example Usage
type USUserProfile = UserProfile<'US'>; // Has US address format
type CAUserProfile = UserProfile<'CA'>; // Has Canadian address format
type GenericUserProfile = UserProfile<'DE'>; // Has Generic (international) address format
`countryCode`'ni `UserProfile` tipiga kiritib va ushbu kodga asoslangan shartli tiplardan foydalanib, siz har bir mintaqa uchun kutilgan formatga mos ravishda `address` tipini dinamik ravishda sozlashingiz mumkin. Bu turli mamlakatlardagi turli xil ma'lumotlar formatlarini tip xavfsizligi ta'minlangan holda boshqarish imkonini beradi.
Xulosa
infer kalit so'zi TypeScript'ning tiplar tizimiga kuchli qo'shimcha bo'lib, shartli tiplar doirasida murakkab tip manipulyatsiyasi va ajratib olish imkonini beradi. infer'ni o'zlashtirish orqali siz yanada mustahkam, tip xavfsizligi ta'minlangan va qo'llab-quvvatlanishi oson kod yaratishingiz mumkin. Funksiyalarning qaytaradigan tiplarini aniqlashdan tortib, murakkab obyektlardan xususiyatlarni ajratib olishgacha, imkoniyatlar keng. Kodingiz uzoq muddatda tushunarli va qo'llab-quvvatlanadigan bo'lib qolishi uchun infer'dan oqilona foydalanishni, aniqlik va o'qilishini birinchi o'ringa qo'yishni unutmang.
Ushbu qo'llanma infer va uning qo'llanilishlari haqida keng qamrovli ma'lumot berdi. Taqdim etilgan misollar bilan tajriba qiling, qo'shimcha foydalanish holatlarini o'rganing va TypeScript'dagi ishlab chiqish jarayoningizni yaxshilash uchun infer'dan foydalaning.